﻿using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Security.Cryptography;
using System.Text;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using System.Data.SqlClient;
using System.Collections;
using System.Collections.Generic;

namespace BfLib.Text
{
    public static class StringLib
    {
        public static string[] MonthsOfTheYear = { String.Empty, "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
        public static string[] MonthsOfTheYearShort = { String.Empty, "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
        private static string AlphaNumericChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";


        #region Conversion

        public static double StrToDoubleDef(string doubleStr, double defaultValue)
        {
            double d = 0.0;
            if (double.TryParse(doubleStr, out d))
            {
                return d;
            }
            else
            {
                return defaultValue;
            }
        }

        public static int StrToIntDef(string s, int d)
        {
            if (s == null) return d;
            int n = d;

            if (int.TryParse(s, out n))
            {
                return n;
            }
            else
                return d;
        }

        public static Int64 StrToInt64Def(string s, Int64 d)
        {
            if (s == null) return d;

            Int64 n = d;

            if (Int64.TryParse(s, out n))
            {
                return n;
            }
            else
                return d;
        }

        public static double KBToMB(int kb)
        {
            decimal mb = (decimal)kb / 1024;
            return (double)decimal.Round(mb, 1);
        }

        public static string KBToMBStr(int kb)
        {
            decimal mb = (decimal)kb / 1024;
            decimal d = decimal.Round(mb, 1);

            return d.ToString();
        }

        #endregion

        #region Random

        public static string RandomIntegerString(int size)
        {
            string charSet = "0123456789";
            StringBuilder builder = new StringBuilder();
            Random random = new Random();
            for (int i = 0; i < size; i++)
            {
                builder.Append(charSet[random.Next(charSet.Length - 1)]);
            }
            return builder.ToString();
        }

        public static int GetCRandomNum(int min, int max)
        {
            if (max == min)
                return min;

            // Create a byte array to hold the random value.
            byte[] randomNumber = new byte[4];

            // Create a new instance of the RNGCryptoServiceProvider.
            RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider();

            // Fill the array with a random value.
            Gen.GetBytes(randomNumber);

            // Convert the byte to an integer value to make the modulus operation easier.
            int rand = Math.Abs(BitConverter.ToInt32(randomNumber, 0));

            // Return the random number mod the number
            // of sides.  The possible values are zero-
            // based, so we add one.
            return Math.Abs(min + (rand % (max - min)));
        }

        public static string GetRandomString(int maxSize)
        {
            char[] chars = new char[40];
            chars =
            "abcdefghijklmnopqrstuvwxyz0123456789-_$!".ToCharArray();
            byte[] data = new byte[1];
            RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
            crypto.GetNonZeroBytes(data);
            data = new byte[maxSize];
            crypto.GetNonZeroBytes(data);
            StringBuilder result = new StringBuilder(maxSize);
            foreach (byte b in data)
            {
                result.Append(chars[b % (chars.Length - 1)]);
            }
            return result.ToString();
        }

        public static int GetRandomNum(int min, int max)
        {
            Random RandomClass = new Random(Convert.ToInt32(DateTime.Now.Ticks % 2100000000));

            if (min >= max)
            {
                min = max - 1;
            }

            return RandomClass.Next(min, max);
        }

        #endregion

        #region HTML and URL encoding

        public static string HtmlEncodeString(string s)
        {
            if (s.Equals(System.DBNull.Value))
                s = string.Empty;

            return System.Web.HttpUtility.HtmlEncode(s);
        }

        public static string HtmlDecodeString(string s)
        {
            return System.Web.HttpUtility.HtmlDecode(s);
        }

        public static string HtmlEncodeString(object s)
        {
            if (s.Equals(System.DBNull.Value))
                s = string.Empty;

            return System.Web.HttpUtility.HtmlEncode(s.ToString());
        }

        public static string HtmlDecodeString(object s)
        {
            if (s.Equals(System.DBNull.Value))
                s = string.Empty;

            return System.Web.HttpUtility.HtmlDecode(s.ToString());
        }

        public static string UrlEncodeString(string s)
        {

            return System.Web.HttpUtility.UrlEncode(s);
        }

        public static string UrlEncodeString(Object obj)
        {
            if (!Object.Equals(obj, null))
                return System.Web.HttpUtility.UrlEncode(obj.ToString());
            else return string.Empty;
        }

        public static string UrlDecodeString(string s)
        {
            return System.Web.HttpUtility.UrlDecode(s);
        }

        #endregion

        #region Cryptography
       
        public static string MD5String(string s)
        {
            // First we need to convert the string into bytes, which
            // means using a text encoder.
            Encoder enc = System.Text.Encoding.Unicode.GetEncoder();

            // Create a buffer large enough to hold the string
            byte[] unicodeText = new byte[s.Length * 2];
            enc.GetBytes(s.ToCharArray(), 0, s.Length, unicodeText, 0, true);

            // Now that we have a byte array we can ask the CSP to hash it
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] result = md5.ComputeHash(unicodeText);

            // Build the final string by converting each byte
            // into hex and appending it to a StringBuilder
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < result.Length; i++)
            {
                sb.Append(result[i].ToString("X2"));
            }

            // And return it
            return sb.ToString();
        }

        public static string SHA1String(string s)
        {
            // First we need to convert the string into bytes, which
            // means using a text encoder.
            Encoder enc = System.Text.Encoding.Unicode.GetEncoder();

            // Create a buffer large enough to hold the string
            byte[] unicodeText = new byte[s.Length * 2];
            enc.GetBytes(s.ToCharArray(), 0, s.Length, unicodeText, 0, true);

            // Now that we have a byte array we can ask the CSP to hash it
            SHA1 sha1 = new SHA1CryptoServiceProvider();
            byte[] result = sha1.ComputeHash(unicodeText);

            // Build the final string by converting each byte
            // into hex and appending it to a StringBuilder
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < result.Length; i++)
            {
                sb.Append(result[i].ToString("X2"));
            }

            // And return it
            return sb.ToString();
        }

        #endregion

        #region Checking and validation

        /// <summary>
        /// Returns the number of somma seperated integers in the string. Returns -1 if the 
        /// string does not consist purely of comma seperated integers. (spaces are allowed in string)
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static int StringIsCommaDelimitedIntegers(string s)
        {
            if (s == null) return -1;

            s = s.Trim();

            if (s.Length == 0) return -1;

            s = s.Replace(" ", string.Empty);
            int test = 0;

            string[] parts = s.Split(',');

            foreach (string temp in parts)
            {
                try
                {
                    if (!int.TryParse(temp, out test))
                    {
                        return -1;
                    }
                }
                catch
                {
                    return -1;
                }
            }
            return parts.Length;
        }

        public static int StringIsCommaDelimitedInt64s(string s)
        {
            if (s == null) return -1;

            s = s.Trim();

            if (s.Length == 0) return -1;

            s = s.Replace(" ", string.Empty);
            Int64 test = 0;

            string[] parts = s.Split(',');

            foreach (string temp in parts)
            {
                try
                {
                    if (!Int64.TryParse(temp, out test))
                    {
                        return -1;
                    }
                }
                catch
                {
                    return -1;
                }
            }
            return parts.Length;
        }

        public static bool IsInteger(String strNumber)
        {
            Regex objIntPattern = new Regex("^[0-9]*$");
            return objIntPattern.IsMatch(strNumber);
        }

        public static bool IsIntegerString(String strNumber)
        {
            Regex objIntPattern = new Regex("^[0-9]*$");
            return objIntPattern.IsMatch(strNumber);
        }

        public static bool IsDouble(string doubleStr)
        {
            double d = 0.0;
            return double.TryParse(doubleStr, out d);
        }

        public static bool IsValidEmailFormat(string emailAddress)
        {
            emailAddress = emailAddress.Trim();
            if (emailAddress == null)
            {
                return false;
            }
            else if ((emailAddress.Length == 0) || (emailAddress.Length > 60))
            {
                return false;
            }
            else
            {
                return Regex.IsMatch(emailAddress, @"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", RegexOptions.IgnorePatternWhitespace);
            }
        }

        public static bool IsInt(string s)
        {
            if (s == null)
            {
                return false;
            }
            int num = 0;
            return int.TryParse(s, out num);
        }

        public static bool IsIntInRange(string s, int iLow, int iHigh)
        {
            int num = 0;
            if (int.TryParse(s, out num))
            {
                return ((num >= iLow) && (num <= iHigh));
            }
            else
            {
                return false;
            }
        }

        public static bool IsGuid(string candidate)
        {
            if (candidate != null)
            {
                return Regex.Match(candidate, @"^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$").Success;
            }
            else
            {
                return false;
            }
        }

        public static bool IsValidUrl(string url)
        {
            string pattern = @"http\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?/?([a-zA-Z0-9\-\._\?\,\'/\\\+&amp;%\$#\=~])*[^\.\,\)\(\s]$";
            Regex reg = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
            return reg.IsMatch(url);
        }

        #endregion

        #region Conversion
        public static int BoolToOneOrZero(bool b)
        {
            if (b)
                return 1;
            else return 0;
        }

        public static string StringArrayToString(string[] strs, string seperator)
        {
            StringBuilder sb = new StringBuilder();
            bool isSeperator = seperator.Length > 0;

            foreach (string s in strs)
            {
                if (isSeperator)
                    sb.Append(String.Format("{0}{1}", s, seperator));
                else
                    sb.Append(s);
            }

            return sb.ToString();
        }

        public static int[] StringArrayToIntArray(string[] strs)
        {
            int[] ids;
            ids = new int[strs.Length];



            try
            {
                for (int n = 0; n < strs.Length; n++)
                {
                    ids[n] = int.Parse(strs[n]);
                }
            }
            catch
            {
                return ids;
            }

            return ids;
        }

        public static int BoolToOneZero(bool b)
        {
            if (b) return 1;
            else return 0;
        }

        public static string BoolToOneZeroStr(bool b)
        {
            if (b) return "1";
            else return "0";
        }

        public static string StringCollToString(StringCollection sc, string seperator)
        {
            StringBuilder sb = new StringBuilder();

            foreach (string s in sc)
            {
                sb.Append(String.Format("{0}{1}", s, seperator));
            }

            return sb.ToString().Trim();
        }

        public static string DBNullToString(Object o)
        {
            if (o == null)
            {
                return string.Empty;
            }
            else if (o.Equals(System.DBNull.Value))
            {
                return string.Empty;
            }
            else
            {
                return o.ToString();
            }
        }

        public static string DBNullToStringDef(Object o, string defaultStr)
        {
            if (o == null)
            {
                return defaultStr;
            }
            else if (o.Equals(System.DBNull.Value))
            {
                return defaultStr;
            }
            else
            {
                return o.ToString();
            }
        }

        public static int DBNullToInt(Object o)
        {
            if (o == null)
            {
                return 0;
            }
            else if (o.Equals(System.DBNull.Value))
            {
                return 0;
            }
            else
            {
                int res = 0;

                if (!int.TryParse(o.ToString(), out res))
                {
                    return 0;
                }
                else
                {
                    return res;
                }
            }
        }

        public static DateTime DBNullToDateTime(object o)
        {
            if ((o == null) || (o.Equals(System.DBNull.Value)))
                return new DateTime(1900, 1, 1);
            else
            {
                try
                {
                    return (DateTime)o;
                }
                catch
                {
                    return new DateTime(1900, 1, 1);
                }
            }
        }

        public static string EnsureString(Object o)
        {
            if (o == null)
            {
                return string.Empty;
            }
            else
            {
                return o.ToString();
            }
        }

        public static bool DBNullToBool(object obj)
        {
            return DBNullToBoolDef(obj, false);
        }

        public static bool DBNullToBoolDef(object obj, bool defaultValue)
        {
            if (obj == null)
                return defaultValue;
            else if (obj.Equals(System.DBNull.Value))
                return defaultValue;
            else
            {
                try
                {
                    return (bool)obj;
                }
                catch
                {
                    return defaultValue;
                }
            }
        }

        #endregion

        #region Parsing & Reading
        public static string GetStringPart(string s, char delimiter, int partnum)
        {
            char[] delim = { delimiter };
            string[] parts = s.Split(delim);

            if (partnum > parts.Length)
            {
                return string.Empty;
            }
            else
            {
                return parts[partnum];
            }

        }

        public static int[] GetIntsFromCommaString(string s)
        {
            char[] sep = { ',' };
            string[] selStrs = s.Split(sep);

            int temp;
            string tmpStr = string.Empty;

            int[] res = new int[selStrs.Length];

            for (int i = 0; i < selStrs.Length; i++)
            {

                tmpStr = selStrs[i].Trim();

                if (int.TryParse(tmpStr, out temp))
                {
                    res[i] = temp;
                }
                else
                {
                    res = new int[1];
                    res[0] = -1;
                    return res;
                }
            }

            return res;
        }

        public static string[] GetStringsFromCommaString(string s)
        {
            char[] sep = { ',' };
            return s.Split(sep);
        }

        public static bool ScContainsStrNoCase(ref StringCollection sc, string s)
        {
            foreach (string tmp in sc)
            {
                if (tmp.ToLower().CompareTo(s.ToLower()) == 0)
                    return true;
            }

            return false;
        }

        public static int GetCharCount(string s, char c)
        {
            int result = 0;
            foreach (char ch in s)
            {
                if (ch == c)
                {
                    result++;
                }
            }

            return result;
        }

        public static int GetCommaListIndex(string s, string value)
        {
            return Array.IndexOf(s.Split(','), value);
        }

        public static bool StringIsCommaSeparatedIntegers(string s)
        {
            if (s == null) return false;

            char[] sep = { ',' };
            string[] selStrs = s.Split(sep);
            int temp;
            string tmpStr = string.Empty;

            foreach (string str in selStrs)
            {
                tmpStr = str.Trim();

                if (tmpStr.Length == 0)
                    continue;

                if (!int.TryParse(tmpStr, out temp))
                {
                    return false;
                }
            }

            return true;
        }

        #endregion

        public static int EnsureInt(object o)
        {
            return EnsureInt(o, 0);
        }

        public static int EnsureInt(object o, int Default)
        {
            if (o == null)
            {
                return Default;
            }
            else
            {
                try
                {
                    return (int)o;
                }
                catch
                {
                    return Default;
                }
            }
        }

        public static DateTime EnsureDateTime(object o)
        {
            return EnsureDateTime(o, DateTime.MinValue);
        }

        public static DateTime EnsureDateTime(object o, DateTime Default)
        {
            if (o == null)
            {
                return Default;
            }
            else
            {
                try
                {
                    return (DateTime)o;
                }
                catch
                {
                    return Default;
                }
            }
        }

        public static string StripQuotes(string s)
        {
            return Regex.Replace(s, "\"\\s*(.|\\n)*?\"", string.Empty);
        }

        #region Replacement and deletion

        public static void ReplaceStrings(ref StringCollection strs, string OldPattern, string NewPattern)
        {
            for(int i=0;i<strs.Count;i++)// string s in strs)
            {
                strs[i] = strs[i].Replace(OldPattern, NewPattern);
            }
        }

        public static void ReplaceStrings(ref StringCollection strs, string OldPattern, string NewPattern, bool FirstInstanceOnly)
        {
            Regex reg = new Regex(OldPattern);

            if (FirstInstanceOnly)
            {
                for (int i = 0; i < strs.Count; i++)// string s in strs)
                {
                    strs[i] = reg.Replace(strs[i], NewPattern, 1);
                    //strs[i] = Regex.Replace(strs[i], OldPattern, NewPattern, RegexOptions.  // strs[i].Replace(OldPattern, NewPattern);
                }
            }
            else
            {
                for (int i = 0; i < strs.Count; i++)// string s in strs)
                {
                    strs[i] = strs[i].Replace(OldPattern, NewPattern);
                }
            }
        }

        public static void ReplaceStringsFirstInstance(ref StringCollection strs, string OldPattern, string NewPattern)
        {
            //string temp = string.Empty;
            Regex reg = new Regex(OldPattern);
            int pos = 0;
 
                for (int i = 0; i < strs.Count; i++)// string s in strs)
                {
                    //temp = strs[i];
                    pos = strs[i].IndexOf(OldPattern);
                    strs[i] = String.Format("{0}{1}{2}", strs[i].Substring(0, pos), NewPattern, strs[i].Substring(pos + OldPattern.Length));
                    //strs[i] = strs[i].Substring(0, pos) + NewPattern + strs[i].Substring(pos + OldPattern.Length);
                    //strs[i] = reg.Replace(strs[i], NewPattern, 1);
                    //strs[i] = Regex.Replace(strs[i], OldPattern, NewPattern, RegexOptions.  // strs[i].Replace(OldPattern, NewPattern);
                }
        }

        public static string RemoveFileExtension(string fileName)
        {
            int i = fileName.LastIndexOf('.');

            if (i < 0)
            {
                return fileName;
            }
            else
            {
                return fileName.Substring(0, i);
            }
        }

        public static string MakeFileNameSafe(string fileName)
        {
            fileName = fileName.Replace(":", "_");
            fileName = fileName.Replace("?", "_");
            fileName = fileName.Replace("\\", "_");
            fileName = fileName.Replace("*", "_");
            fileName = fileName.Replace("<", "_");
            fileName = fileName.Replace(">", "_");
            fileName = fileName.Replace("/", "_");
            fileName = fileName.Replace("|", "_");
            fileName = fileName.Replace("\"", "_");

            return fileName;
        }

        public static string MinimizeSpaces(string s)
        {
            while (s.IndexOf("  ") >= 0)
            {
                s = s.Replace("  ", " ");
            }

            return s.Trim();
        }

        public static string[] RemoveDuplicateStrings(string[] strs, bool trimStrings, bool sortResult)
        {
            if (trimStrings)
            {
                for (int i = 0; i < strs.Length; i++)
                {
                    strs[i] = strs[i].Trim();
                }
            }

            StringCollection sc = new StringCollection();

            for (int i = 0; i < strs.Length; i++)
            {
                if (ScContainsStrNoCase(ref sc, strs[i]))
                    continue;

                sc.Add(strs[i]);
            }

            strs = new string[sc.Count];

            for (int i = 0; i < sc.Count; i++)
            {
                strs[i] = sc[i];
            }

            sc.Clear();
            if (sortResult) Array.Sort(strs);
            return strs;
        }

        public static string RemoveAllHtmlTagsAndLimitLength(string html, int maxsize, bool AddEpsilon)
        {
            html = RemoveAllHtmlTags(html);

            if (html.Length == 0) return html;
            if (maxsize <= 0) return html;

            if (AddEpsilon)
            {
                return String.Format("{0}...", LimitStringLength(html, maxsize));
            }
            else
            {
                return LimitStringLength(html, maxsize);
            }
        }

        public static string LimitStringLength(string s, int maxAllowedLength)
        {
            if (s == null)
            {
                return string.Empty;
            }
            else if (s.Length <= maxAllowedLength)
            {
                return s;
            }
            else
            {
                return s.Substring(0, maxAllowedLength).Trim();
            }
        }

        public static string LimitStringLengthEpsillon(string s, int maxAllowedLength)
        {
            const string el = "...";
            if (s == null)
            {
                return string.Empty;
            }
            else if (s.Length <= maxAllowedLength - 3)
            {
                return s;
            }
            else if (s.Length < 3)
            {
                return el;
            }
            else
            {
                return String.Concat(s.Substring(0, maxAllowedLength - 3).Trim(), el);
            }
        }

        public static string RemoveUnsupportedHtmlTags(string input)
        {
            input = StringLib.HtmlDecodeString(input);
            string output = string.Empty;
            // break the comments so someone cannot add an open comment
            input = input.Replace("<!--", string.Empty);

            // strip out comments and doctype
            Regex docType = new Regex("<!DOCTYPE[.]*>");
            output = docType.Replace(input, string.Empty);

            // add target="_blank" to hrefs and remove parts that are 
            // not supported
            output = Regex.Replace(output, "(.*)", @"$5");

            //strip out most known tags except (a|b|br|blockquote|em|h1|h2|
            //h3|h4|h5|h6|hr|i|li|ol|p|u|ul|strong|sub|sup)
            Regex badTags = new Regex("< [/]{0,1}(abbr|acronym|address|applet|area|base|basefont|bdo|big|body|button|caption|center|cite|code|col|colgroup|dd|del|dir|div|dfn|dl|dt|embed|fieldset|font|form|frame|frameset|head|html|iframe|img|input|ins|isindex|kbd|label|legend|link|map|menu|meta|noframes|noscript|object|optgroup|option|param|pre|q|s|samp|script|select|small|span|strike|style|table|tbody|td|textarea|tfoot|th|thead|title|tr|tt|var|xmp){1}[.]*>");
            return badTags.Replace(output, string.Empty);
        }

        public static string RemoveAllHtmlTags(string html)
        {
            if (html == null) { return string.Empty; }

            html = Regex.Replace(html, "<(.|\n)*?>", string.Empty);
            html = html.Replace("#0026;", string.Empty);        //Unicode & or double decoded &amp;
            html = StringLib.HtmlDecodeString(html).Trim();
            html = html.Replace("\"", "&quot;");
            //html = html.Replace("'", string.Empty);
            html = html.Replace(@"\", @"\\");
            html = html.Replace(@"\\\\", @"\\");
            //disable someoneputting a broken comment in to disable the rest of the page
            html = html.Replace("<", "&lt;");
            return html.Replace(">", "&gt;");

        }

        public static string RemoveHtmlTagsOnly(string s)
        {
            if (s == null) { return string.Empty; }
            return Regex.Replace(s, "<(.|\n)*?>", string.Empty);
        }

        public static string StripTagsCharArray(string source)
        {
            char[] array = new char[source.Length];
            int arrayIndex = 0;
            bool inside = false;

            for (int i = 0; i < source.Length; i++)
            {
                char let = source[i];
                if (let == '<')
                {
                    inside = true;
                    continue;
                }
                if (let == '>')
                {
                    inside = false;
                    continue;
                }
                if (!inside)
                {
                    array[arrayIndex] = let;
                    arrayIndex++;
                }
            }
            return new string(array, 0, arrayIndex);
        }

        public static string RemoveHTMLScripts(string html)
        {
            return Regex.Replace(html, @"<script(.|\n)*?>(.|\n)*?</script>", string.Empty, RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
        }

        public static string RemoveHTMLComments(string html)
        {
            return Regex.Replace(html, @"<!--(.|\n)*?-->", string.Empty, RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
        }

        public static DateTime UnixStrToDateTime(string UnixTimeAsStr, bool IsSeconds)
        {
            long ut = StrToInt64Def(UnixTimeAsStr, 0);
            DateTime dt = new DateTime(1970,1,1);
            if (IsSeconds)
            {
                return dt.AddSeconds(ut);
            }
            else
            {
                return dt.AddMilliseconds(ut);
            }
        }


        #endregion

        #region Color methods
        public static System.Drawing.Color RandomColor()
        {
            Random random = new Random(DateTime.Now.Millisecond * DateTime.Now.Second);
            byte r = (byte)random.Next(0, 255);
            byte g = (byte)random.Next(0, 255);
            byte b = (byte)random.Next(0, 255);

            return System.Drawing.Color.FromArgb(r, g, b);
        }

        public static string RandomHTMLColor()
        {
            Random rnd = new Random(DateTime.Now.Millisecond * DateTime.Now.Second);
            int a, b, c;
            a = rnd.Next(256);
            b = rnd.Next(256);
            c = rnd.Next(256);

            return String.Format("{0}{1}{2}", a.ToString("X2"), b.ToString("X2"), c.ToString("X2"));
        }

        public static string ColorToHtmlStr(System.Drawing.Color c)
        {
            return System.Drawing.ColorTranslator.ToHtml(c);
        }

        public static System.Drawing.Color HtmlStrToColor(string HtmlColor)
        {
            try
            {
                return System.Drawing.ColorTranslator.FromHtml(HtmlColor);
            }
            catch//(Exception ex)
            {
                return System.Drawing.Color.Black;
            }
        }
        #endregion

        #region Misc
        public static string Reverse(string str)
        {
            char[] arr = str.ToCharArray();
            Array.Reverse(arr);
            return new string(arr);
        }
  
        public static string GetTextAfterLastInstanceOf(string s, char c)
        {
            int i = s.LastIndexOf(c);

            if (i < 0)
                return string.Empty;

            return s.Substring(i + 1, s.Length - i - 1);
        }

        public static string MsToHoursMinSec(int mseconds)
        {
            int hrs = mseconds / 3600000;
            mseconds = mseconds - (hrs * 3600000);

            var mins = mseconds / 60000;
            mseconds = mseconds - (mins * 60000);

            int secs = mseconds / 1000;

            return String.Format("{0}:{1}:{2}", PadInt(hrs, 2), PadInt(mins, 2), PadInt(secs, 2));
        }
      
        public static string SlugifyTitle(string title)
        {
            title = title.ToLower();

            foreach (char c in title)
            {
                if (AlphaNumericChars.IndexOf(c) >= 0)
                {
                    title = title.Replace(c, '_');
                }
            }

            return String.Format("{0}_{1}", RandomIntegerString(5), title);
        }

        public static string ChangeFileExtension(string fileName, string newExt)
        {
            return System.IO.Path.ChangeExtension(fileName, newExt);
        }

        public static string GetNthOfInteger(int i)
        {
            string th = "th", st = "st", rd = "rd", nd = "nd";
            if ((i >= 11) && (i <= 13)) return th;

            i = i % 10;

            //st, nd, rd, th, th, th, th, th, th, th
            switch (i)
            {
                case 1:
                    {
                        return st;
                    }
                case 2:
                    {
                        return nd;
                    }
                case 3:
                    {
                        return rd;
                    }
                default:
                    {
                        return th;
                    }
            }
        }

        public static int IntOverIntAsPercent(int enumerator, int denominator)
        {
            double d = Convert.ToDouble(denominator);
            double e = Convert.ToDouble(enumerator);
            return Convert.ToInt32(Math.Ceiling((e / d) * 100));
        }
     
        public static string PadInt(int i, int maxWidth)
        {
            int diffLen = maxWidth - i.ToString().Length;
            if (diffLen <= 0) return i.ToString();
            string s = new string('0', diffLen);
            return string.Format("{0}{1}", s, i);
        }

        #endregion

        /// <summary>
        /// Gets the value of an attribute from a HTML tag. It's more fault tolerant than XML parsers
        /// and it's quite fast too.
        /// </summary>
        /// <param name="tag">A HTML tag</param>
        /// <param name="attrib">The name of the HTML attribute</param>
        /// <returns>The value of the specified HTML attribute</returns>
        public static string GetAttibute(string tag, string attrib)
        {
            char quoteChar, nonQuoteChar;
            char quoteSingle='\'', quoteDouble = '\"';
            int i,j;
            StringBuilder sb = new StringBuilder();

            tag = reducesAttributeSpaces(tag);
            i = tag.IndexOf(String.Concat(attrib,"="));

            if(i>=0)
            {
                i = i + attrib.Length;
            }
            else
            {
                return string.Empty;
            }


            if ((tag[i + 1] == quoteSingle) || (tag[i + 1] == quoteDouble))
            {
                quoteChar = tag[i + 1];
                if (quoteChar == quoteSingle) nonQuoteChar = quoteDouble;
                else nonQuoteChar = quoteSingle;


                j = i + 2;
                while ((tag[j] != quoteChar) && (j < tag.Length) && (tag[j] != '>'))// && (tag[j] != nonQuoteChar))
                {
                    sb.Append(tag[j]);
                    j++;
                }
            }
            else
            {
                j = i + 1;
                while ((tag[j] != ' ') && (j < tag.Length) && (tag[j] != '>'))
                {
                    sb.Append(tag[j]);
                    j++;
                }
            }

            return sb.ToString();
        }

        private static string reducesAttributeSpaces(string s)
        {
            s = s.Replace("\t", string.Empty);
            while (s.IndexOf("   ") >= 0)
            {
                s = s.Replace("   ", " ");
            }
            while (s.IndexOf("  ") >= 0)
            {
                s = s.Replace("  ", " ");
            }

            while (s.IndexOf("= ") >= 0)
            {
                s = s.Replace("= ", "=");
            }
            while (s.IndexOf(" =") >= 0)
            {
                s = s.Replace(" =", "=");
            }

            return s;

        }

        public static bool RegexpContains(string s, string re)
        {
            return Regex.IsMatch(s, re, RegexOptions.IgnoreCase);
        }

        public static List<string> RegexpGetMatches(string s, string re, int? GroupIndex)
        {
            List<string> result = new List<string>();
            //string regexp = @"\ {1}([a-z0-9]*[^<>])=";

            try
            {
                Regex regexObj = new Regex(re, 
                        RegexOptions.Singleline | 
                        RegexOptions.IgnoreCase | 
                        RegexOptions.Multiline | 
                        RegexOptions.IgnorePatternWhitespace);

                Match matchResults = regexObj.Match(s);
                while (matchResults.Success)
                {
                    if (GroupIndex != null)
                    {
                        if (GroupIndex.HasValue)
                        {
                            if (matchResults.Groups.Count > GroupIndex.Value)
                            {
                                result.Add(matchResults.Groups[GroupIndex.Value].Value);
                            }
                        }
                    }
                    else
                    {
                        result.Add(matchResults.Value);
                    }
                    // matched text: matchResults.Value
                    // match start: matchResults.Index
                    // match length: matchResults.Length
                    matchResults = matchResults.NextMatch();
                }
            }
            catch// (ArgumentException ex)
            {
                // Syntax error in the regular expression
            }

            return result;
        }

        public static int RegexpGetMatchCount(string s, string re)
        {
            Regex regex = new Regex(re, RegexOptions.IgnoreCase);
            int result = 0;
            MatchCollection mc = regex.Matches(s);
            foreach (Match m in mc)
            {
                result++;
            }
            return result;
        }
    }
}
